package com.cqeec.demo.util;

import java.awt.AlphaComposite;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.Rectangle;
import java.awt.RenderingHints;
import java.awt.color.ColorSpace;
import java.awt.image.BufferedImage;
import java.awt.image.ColorConvertOp;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;

import javax.imageio.ImageIO;
import javax.imageio.ImageReadParam;
import javax.imageio.ImageReader;
import javax.imageio.stream.ImageInputStream;
import javax.swing.ImageIcon;

import com.mortennobel.imagescaling.ResampleOp;

/**
 * 图片处理工具类
 * 
 * @Title: ImageUtil
 * @Descripton: 对图片上传进行处理，包括缩放图像、剪切图像、图像类型转换、彩色转黑白、文字水印、图片水印等
 */
public class ImageUtil {
	
	/**
	 * 根据数据创建字图
	 * 
	 * @param fontString 造字数组
	 * @param saveImagePath 保存路径
	 */
	public final static void createFontImage(String fontString, String saveImagePath) {
		try {
			if (fontString.contains(",")) {
				String[] tempArray = fontString.split(",");
				
				// 根据数组的长度开方后得到要生成的图片的宽和高
				int width = NumberUtil.numberSqrt(tempArray.length);
				int height = width;
				
				// 根据宽和高生成空白图
				BufferedImage bi = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
				
				// 根据图的宽和高来设置像素点
				int m = 0;
				for (int x = 0; x < width; x++) {
					for (int y = 0; y < height; y++) {
						if (NumberUtil.stringNumberToInt(tempArray[m]) == 1) {
							Graphics graphic = bi.getGraphics();
							graphic.setColor(Color.BLACK);
							graphic.fillRect(y, x, 1, 1);
						}
						m += 1;
					}
				}
				ImageIO.write(bi, "PNG", new File(saveImagePath));
			} else {
				// 根据数组的长度开方后得到要生成的图片的宽和高
				int width = NumberUtil.numberSqrt(fontString.length());
				int height = width;
				
				// 根据宽和高生成空白图
				BufferedImage bi = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
				
				// 根据图的宽和高来设置像素点
				int m = 0;
				for (int x = 0; x < width; x++) {
					for (int y = 0; y < height; y++) {
						if (NumberUtil.stringNumberToInt(String.valueOf(fontString.charAt(m))) == 1) {
							Graphics graphic = bi.getGraphics();
							graphic.setColor(Color.BLACK);
							graphic.fillRect(y, x, 1, 1);
						}
						m += 1;
					}
				}
				ImageIO.write(bi, "PNG", new File(saveImagePath));
			}
		} catch (IOException e) {
		}
		
	}

	/**
	 * 缩放图片（按指定的高度和宽度缩放）
	 * 
	 * @param srcImagePath   源图像文件地址
	 * @param scaleImagePath 缩放后的图像地址
	 * @param width          缩放后的宽度
	 * @param height         缩放后的高度
	 */
	public final static void resize(String srcImagePath, String scaleImagePath, int width, int height) {
		try {
			BufferedImage inputBufImage = ImageIO.read(new File(srcImagePath));
			ResampleOp resampleOp = new ResampleOp(width, height);// 转换
			BufferedImage rescaledTomato = resampleOp.filter(inputBufImage,null);
			String mimeType = getFileExt(srcImagePath); // 文件扩展名
			ImageIO.write(rescaledTomato, mimeType, new File(scaleImagePath));
		} catch (IOException e) {
		}
	}
	
	/**
	 * 图像切割(按指定起点坐标和宽高切割)
	 * 
	 * @param srcImagePath  源图像地址
	 * @param cutImagePath  剪切图像地址
	 * @param x             剪切起点坐标X
	 * @param y             剪切起点坐标Y
	 * @param width         剪切宽度
	 * @param height        剪切高度
	 */
	public final static void cut(String srcImagePath, String cutImagePath, int x, int y,int width, int height) {
		ImageInputStream iis = null;
		try {
			iis = ImageIO.createImageInputStream(new FileInputStream(srcImagePath));
			Iterator<ImageReader> iterator = ImageIO.getImageReaders(iis);
			ImageReader reader = (ImageReader) iterator.next();
			reader.setInput(iis, true);
			ImageReadParam param = reader.getDefaultReadParam();
			Rectangle rectangle = new Rectangle(x, y, width, height);
			param.setSourceRegion(rectangle);
			BufferedImage bi = reader.read(0, param);
			String mimeType = getFileExt(srcImagePath);
			ImageIO.write(bi, mimeType, new File(cutImagePath));
		} catch (Exception e) {
		} finally {
			if (iis != null) {
				try {
					iis.close();
				} catch (IOException e) {
				}
			}
		}
	}

	
	/**
	 * 返回指定图片的中心坐标
	 * 
	 * @param srcImgPath 源图地址
	 * @return 返回图片坐标
	 */
	public final static Map<String, Integer> point(String srcImgPath) {
		Map<String, Integer> coordinate = new HashMap<String, Integer>();
		try {
			BufferedImage bufferedImage = ImageIO.read(new File(srcImgPath));
			int width = bufferedImage.getWidth();   // 图片宽度
			int height = bufferedImage.getHeight(); // 图片高度
			
			int x = width / 2;
			int y = height / 2;
			
			coordinate.put("x", x);
			coordinate.put("y", y);
			
			return coordinate;
		} catch (IOException e) {
			coordinate.put("x", 0);
			coordinate.put("y", 0);
			
			return coordinate;
		}
	}

	/**
	 * 图像类型转换：GIF->JPG、GIF->PNG、PNG->JPG、PNG->GIF(X)、BMP->PNG
	 * 
	 * @param srcImageFile  源图像地址
	 * @param formatName    包含格式非正式名称的 String：如JPG、JPEG、GIF等
	 * @param destImageFile 目标图像地址
	 */
	public final static void convert(String srcImageFile, String formatName, String destImageFile) {
		try {
			File f = new File(srcImageFile);
			f.canRead();
			f.canWrite();
			BufferedImage src = ImageIO.read(f);
			ImageIO.write(src, formatName, new File(destImageFile));
		} catch (Exception e) {
		}
	}

	/**
	 * 彩色转为黑白
	 * 
	 * @param srcImagePath  源图像地址
	 * @param destImagePath 目标图像地址
	 */
	public final static void gray(String srcImagePath, String destImagePath) {
		try {
			BufferedImage src = ImageIO.read(new File(srcImagePath));
			ColorSpace cs = ColorSpace.getInstance(ColorSpace.CS_GRAY);
			ColorConvertOp op = new ColorConvertOp(cs, null);
			src = op.filter(src, null);
			String mimeType = getFileExt(srcImagePath);
			ImageIO.write(src, mimeType, new File(destImagePath));
		} catch (IOException e) {
		}
	}

	/**
	 * 给图片添加文字水印
	 * 
	 * @param waterText    水印文字
	 * @param srcImgPath   源图像地址
	 * @param destImgPath  目标图像地址
	 * @param position     位置：1、左上角，2、右上角，3、左下角，4、右下角，5、正中间
	 * @param alpha        透明度：alpha 必须是范围 [0.0, 1.0] 之内的一个浮点数字
	 */
	public final static void markImageByText(String waterText, String srcImgPath,
			String destImgPath, int position, float alpha) {
		
		InputStream is = null;
        OutputStream os = null;
        
		try {
			Image srcImg = ImageIO.read(new File(srcImgPath));
			
			int width  = srcImg.getWidth(null);
			int height = srcImg.getHeight(null);
			
			BufferedImage buffImg = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
			Graphics2D g = buffImg.createGraphics();// 得到画笔对象
			// 设置对线段的锯齿状边缘处理 
            g.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
            g.drawImage(srcImg.getScaledInstance(width, height, Image.SCALE_SMOOTH), 0, 0, null);
            g.setColor(Color.WHITE);// 设置颜色
            int fontSize = 30;
            g.setFont(new Font("宋体", Font.BOLD, fontSize));// 设置 Font
            
            int waterTextW = getLength(waterText) * fontSize;
            int waterTextH = fontSize;
            
			// 根据位置参数确定坐标位置
			int x = 0;
			int y = 0;
			switch(position){
				case 1:
					y = waterTextH;
					break;
				case 2:
					x = width - waterTextW - 10;
					y = waterTextH;
					break;
				case 3:
					y = height - waterTextH;
					break;
				case 4:
					x = width - waterTextW - 10;
					y = height - waterTextH;
					break;
				case 5:
					x = (width - waterTextW) / 2;
					y = (height - waterTextH) / 2;
					break;
				default:
					y = waterTextH;
					break;
			}
			
			g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_ATOP, alpha));
			// 在指定坐标绘制水印文字：第一参数->设置的内容，后面两个参数->文字在图片上的坐标位置(x,y) . 
            g.drawString(waterText, x, y);
            // 释放资源
			g.dispose();
			os = new FileOutputStream(destImgPath);
			// 生成图片 
            ImageIO.write(buffImg, "JPG", os);
		} catch (Exception e) {
		} finally {
            try {
                if (null != is) is.close();
            } catch (Exception e) {
            }
            try {
                if (null != os) os.close();
            } catch (Exception e) {
            }
        }
	}

	/**
	 * 给图片添加图片水印
	 * 
	 * @param waterIcon    水印图片
	 * @param srcImgPath   源图像地址
	 * @param destImgPath  目标图像地址
	 * @param position     位置：1、左上角，2、右上角，3、左下角，4、右下角，5、正中间
	 * @param alpha        透明度：alpha 必须是范围 [0.0, 1.0] 之内的浮点数字
	 */
	public final static void markImageByIcon(String waterIcon, String srcImgPath, 
			String destImgPath, int position, float alpha) {
		
		OutputStream os = null;
		
		try {
			Image srcImg = ImageIO.read(new File(srcImgPath));
			
			int width = srcImg.getWidth(null);
			int height = srcImg.getHeight(null);
			
			BufferedImage buffImg = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
			
			// 得到画笔对象
			Graphics2D g = buffImg.createGraphics();
			
			// 设置对线段锯齿状边缘处理
			g.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
			
			g.drawImage(srcImg.getScaledInstance(width, height, Image.SCALE_SMOOTH), 0, 0, null);
			
			// 水印图片的路径，水印一般格式是gif，png,这种图片可以设置透明度
			ImageIcon imgIcon = new ImageIcon(waterIcon);
			
			// 得到Image对象
			Image water = imgIcon.getImage();
			
			int waterW = water.getWidth(null);
			int waterH = water.getHeight(null);
			
			// 如果水印图片高或者宽大于目标图片是做的处理,使其水印宽或高等于目标图片的宽高，并且等比例缩放
			int new_waterW = waterW;
			int new_waterH = waterH;
			
			if(waterW > width){
				new_waterW = width;
				new_waterH = (int) ((double)new_waterW/waterW*height);
			}
			if(waterH > height){
				new_waterH = height;
				new_waterW = (int) ((double)new_waterH/waterH*new_waterW);
			}
			
			// 根据位置参数确定坐标位置
			int x = 0;
			int y = 0;
			switch(position){
				case 1:
					x = 20;
					y = 20;
					break;
				case 2:
					x = width - new_waterW - 20;
					y = 20;
					break;
				case 3:
					x = 20;
					y = height - new_waterH - 20;
					break;
				case 4:
					x = width - new_waterW - 20;
					y = height - new_waterH - 20;
					break;
				case 5:
					x = (width - new_waterW)/2;
					y = (height - new_waterH)/2;
					break;
				default:
					break;
			}
			
			g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_ATOP, alpha));
			
			// 水印图片的位置
			g.drawImage(water, x, y, new_waterW, new_waterH, null);
			
			g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER));
			
			// 释放资源
			g.dispose();
			
			os = new FileOutputStream(destImgPath);
			
			// 生成图片
			ImageIO.write(buffImg, "JPG", os);

		} catch (Exception e) {
		} finally {
			try{
				if(null != os) os.close();
			}catch(Exception e){
			}
		}
	}
	
	/**
	 * 对图片进行无损旋转
	 * 
	 * @param srcImgPath   源图片路径
	 * @param destImgPath  旋转后图片路径
	 * @param angel        旋转角度
	 */
	public final static void rotateImage(String srcImgPath, String destImgPath, int angel) {
		
		OutputStream os = null;
		
		try {
			BufferedImage srcImg = ImageIO.read(new File(srcImgPath));
			
			int width = srcImg.getWidth(null);
			int height = srcImg.getHeight(null);
	        
			Rectangle src = new Rectangle(new Dimension(width, height));
			
			if (angel >= 90) {
				if(angel / 90 % 2 == 1){
					int temp = src.height;
					src.height = src.width;
					src.width = temp;
				}
				angel = angel % 90;
			}
			
			double r = Math.sqrt(src.height * src.height + src.width * src.width) / 2;
			double len = 2 * Math.sin(Math.toRadians(angel) / 2) * r;
			double angel_alpha = (Math.PI - Math.toRadians(angel)) / 2;
			double angel_dalta_width = Math.atan((double) src.height / src.width);
			double angel_dalta_height = Math.atan((double) src.width / src.height);

			int len_dalta_width = (int) (len * Math.cos(Math.PI - angel_alpha - angel_dalta_width));
			int len_dalta_height = (int) (len * Math.cos(Math.PI - angel_alpha - angel_dalta_height));
			int des_width = src.width + len_dalta_width * 2;
			int des_height = src.height + len_dalta_height * 2;
			
			Rectangle rect = new Rectangle(new Dimension(des_width, des_height));
			
			BufferedImage bufImg = new BufferedImage(rect.width, rect.height, BufferedImage.TYPE_INT_RGB);
			
			Graphics2D g = bufImg.createGraphics();
			
			g.fillRect(0, 0, rect.width, rect.height);
			g.setBackground(new Color(0.1f,0.2f,0.2f,0.0f));
			
			g.translate((rect.width - width) / 2, (rect.height - height) / 2);
			g.rotate(Math.toRadians(angel), width / 2, height / 2);
			
			g.drawImage(srcImg, null, null);
			
			// 释放资源
			g.dispose();
			
			os = new FileOutputStream(destImgPath);
			
			// 生成图片
			ImageIO.write(bufImg, "JPG", os);
			
		} catch (Exception e) {
		} finally {
			try{
				if(null != os) os.close();
			}catch(Exception e){
			}
		}
	}
	
	/**
	 * 计算水印文字的长度（一个中文算两个字符）
	 * 
	 * @param waterText 水印文字
	 * @return          返回水印文字长度
	 */
	private final static int getLength(String waterText) {
		int length = 0;
		
		for (int i = 0; i < waterText.length(); i++) {
			if (new String(waterText.charAt(i) + "").getBytes().length > 1) {
				length += 2;
			} else {
				length += 1;
			}
		}
		return length / 2;
	}
	
	/**
	 * 获取文件扩展名
	 * 
	 * @param filePath 文件路径
	 * @return 返回扩展名
	 */
	public static String getFileExt(String filePath) {
		if(filePath == null || "".equals(filePath)) return null;
		return filePath.substring(filePath.lastIndexOf(".") + 1).toLowerCase();
	}

}
